/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.tnmk.worktime.log;

public final class LogUtils {

  private LogUtils() {
  }
  public static int callerId = 0;
  private static final int OUTSIDE_INIT_LEVEL = 3;

  public static String getCallerLog(Object caller, int initLevel, int levels) {
    StringBuilder rs = new StringBuilder();
    StackTraceElement[] stacks = Thread.currentThread().getStackTrace();
//    for (int i = 0; i < 5; i++) {
//      System.out.println("" + i + "> " + stacks[i]);
//    }
    String hashCode = "";
    if (caller != null) {
      hashCode = "@" + caller.hashCode();
    }
    StackTraceElement stack = stacks[initLevel];
    rs.append(getCaller(stack, hashCode));
    for (int i = 1; i < levels; i++) {
      int index = initLevel + i;
      if (index > stacks.length - 1) {
        break;
      }
      stack = stacks[index];
      rs.append("\n" + getCaller(stack, null));
    }
//    rs.append("\n\tat "+stack.getClassName()+"."+stack.getMethodName()+"("+stack.getFileName()+":"+stack.getLineNumber()+")");
    return rs.toString();
  }

  private static String getCaller(StackTraceElement stack, String hashCodeStr) {
    String rs;
    String hashCode = hashCodeStr;
    if (hashCode == null) {
      hashCode = "";
    }
    String className = stack.getClassName();
    String[] cnParts = className.split("\\.");
    className = cnParts[cnParts.length - 1];
    String methodName = stack.getMethodName();
    rs = "<<T " + Thread.currentThread().getId() + "-" + callerId + "\tat (" + stack.getFileName() + ":" + stack.getLineNumber() + ") " + hashCode + "." + methodName + "() >>";
    return rs;
  }
  public static int printCaller(Object caller) {
    return printCaller(caller, null, OUTSIDE_INIT_LEVEL + 1, 1);
  }
  
  public static int printCaller(Object caller, String s) {
    return printCaller(caller, s, OUTSIDE_INIT_LEVEL + 1, 1);
  }

  public static int printCaller(Object caller, String s, int levels) {
    return printCaller(caller, s, OUTSIDE_INIT_LEVEL + 1, levels);
  }
  /**
   * @param caller
   * @param s
   * @param initLevel If application code can call this method directly, use initLevel as 1.
   * @param levels
   * @return 
   */
  private static int printCaller(Object caller, String s, int initLevel, int levels) {
    callerId++;
    String scaller = getCallerLog(caller, initLevel, levels);
    if (s != null) {
      scaller += s;
    }
    System.out.println(scaller);
    return callerId;
  }

  public static void printChild(int callerId, String s) {
    System.out.println("\t<<" + Thread.currentThread().getId() + "-" + callerId + ">> " + s);
  }
//  public static String getCallerId() {
//    return "\t{"+callerId+"}";
//  }
}
